#ifndef RP2MATRIX3_H
#define RP2MATRIX3_H

#include "Rp2System.h"
#include "Rp2Vector3.h"

namespace Rp2
{

// Stored in Row Major form.
// Translation:  v * M, v is a row vector.

template <class Real>
class Matrix3
{
public:
	Matrix3(bool bZero = true);

	Matrix3(Real f00, Real f01, Real f02,
			Real f10, Real f11, Real f12,
			Real f20, Real f21, Real f22);
	// copy
	Matrix3(const Matrix3& rkM);

	// member access
	inline operator Real* ();
	inline operator const Real* () const;
	inline Real& operator[] (int iEntry);
    Vector3<Real> GetRow (int iRow) const;
    Vector3<Real> GetColumn (int iCol) const;

	// Create rotation matrices (positive angle - counterclockwise).  The
	// angle must be in radians, not degrees.
	Matrix3(const Vector3<Real>& rkAxis, Real fAngleRad);

	// comparison
	bool operator== (const Matrix3& rkM) const;
	bool operator!= (const Matrix3& rkM) const;
	bool operator<  (const Matrix3& rkM) const;
	bool operator<= (const Matrix3& rkM) const;
	bool operator>  (const Matrix3& rkM) const;
	bool operator>= (const Matrix3& rkM) const;

	// arithmetic operations
	inline Matrix3 operator* (const Matrix3& rkM) const;
	inline Matrix3 operator* (Real fScalar) const;

	// transformation
	inline Vector3<Real> operator* (const Vector3<Real>& rkV) const; //M * v^T
	
	// other operations
	Matrix3& FromAxisAngle(const Vector3<Real>& rkAxis, Real fAngleRad);
	Matrix3& MakeZero();
	Matrix3& MakeIdentity();
    Matrix3 Inverse () const;
	Matrix3 Transpose() const; //M^t
    Matrix3 TransposeTimes (const Matrix3& rkM) const;  // this^T * M
    Matrix3 TimesTranspose (const Matrix3& rkM) const;  // this * M^T
	Matrix3 DiagonalTimes(const Vector3<Real>& rkDiag) const;
	Matrix3 TimesDiagonal(const Vector3<Real>& rkDiag) const;
	Real Determinant () const;
    Real QForm (const Vector3<Real>& rkU,
        const Vector3<Real>& rkV) const;  // u^T*M*v

    void Orthonormalize ();

	// debug
	void Print();

	static const Matrix3 ZERO;
	static const Matrix3 IDENTITY;
protected:
	Real m_afTuple[9];

	int CompareArrays (const Matrix3& rkM) const;
};

// v * M
template <class Real>
inline Vector3<Real> operator* (const Vector3<Real>& rkV, const Matrix3<Real>& rkM);

#include "Rp2Matrix3.inl"
typedef Matrix3<float> Matrix3f;
typedef Matrix3<double> Matrix3d;

}

#endif